﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Kokomo.Mirror.CliMetadata.Tables;
using Kokomo.Mirror.CliMetadata.Signatures;

namespace Kokomo.Mirror.CliMetadata
{
	class CliParameterInfo : ParameterInfo
	{
		//private ParamRow _paramRow;
		private string _name;
		private ParameterAttributes _flags;
		internal MethodBase owner;
		private int _sequence;
		internal Param signature;
		private CliMemberBasicInfo basicInfo;

		internal CliParameterInfo(
			CliMemberBasicInfo basicInfo,
			string name,
			ParameterAttributes flags,
			int sequence,
			Param signature,
			Type parameterType = null
			)
		{
			//this._paramRow = paramRow;
			this.basicInfo = basicInfo;
			//this._owner = owningMethod;
			this._sequence = sequence;
			this.signature = signature;
			this._name = name;
			this._flags = flags;
			this._type = parameterType;
			//this._customAttributeData = new Lazy<IList<CustomAttributeData>>(this.LoadCustomAttributeData);
			//this._optionalModifiers = new Lazy<Type[]>(this.LoadOptionalModifiers);
			//this._requiredModifiers = new Lazy<Type[]>(this.LoadRequiredModifiers);
			//this._defaultValue = new Lazy<object>(this.LoadDefaultValue);
		}

		private Type _type;
		public override Type ParameterType
		{
			get
			{
				if ((object)this._type == null)
				{
					Type[] genericTypeArguments = null;
					if ((object)this.owner.DeclaringType != null)
						genericTypeArguments = this.owner.DeclaringType.GetGenericArguments();
					Type[] genericMethodArguments =
						(this.owner.IsGenericMethod)	// Fails for ConstructorInfo
						? this.owner.GetGenericArguments()
						: null
						;

					this._type = this.signature.ResolveType(
						this.basicInfo.module,
						true,
						genericTypeArguments,
						genericMethodArguments
						);
				}

				return this._type;
			}
		}
		public override ParameterAttributes Attributes
		{
			get { return this._flags; }
		}
		public override int Position
		{
			get
			{
				return this._sequence - 1;
			}
		}

		//private Lazy<object> _defaultValue;
		private object LoadDefaultValue()
		{
			return this.basicInfo.module.QueryConstantValue(this.MetadataToken);
		}
		public override object DefaultValue
		{
			get
			{
				//return this._defaultValue.Value; 
				return this.LoadDefaultValue();
			}
		}
		public override object RawDefaultValue
		{
			get
			{
				//return this._defaultValue.Value;
				return this.LoadDefaultValue();
			}
		}
		#region Attributes

		//private Lazy<IList<CustomAttributeData>> _customAttributeData;
		//private IList<CustomAttributeData> LoadCustomAttributeData()
		//{
		//    return this.basicInfo.module.GetCustomAttributesFor(this.MetadataToken);
		//}
		public override IList<CustomAttributeData> GetCustomAttributesData()
		{
			return this.basicInfo.module.GetCustomAttributesFor(this.MetadataToken);
			//return this._customAttributeData.Value;
		}
		#endregion

		public override bool IsDefined(Type attributeType, bool inherit)
		{
			return this.basicInfo.module.IsAttributeDefinedOn(this.MetadataToken, attributeType, inherit);
		}

		public override int MetadataToken
		{
			get { return this.basicInfo.token; }
		}

		//private Lazy<Type[]> _optionalModifiers;
		private Type[] LoadOptionalModifiers()
		{
			if (this.signature.customModifiers == null)
				return Type.EmptyTypes;

			return this.signature.customModifiers.OptionalModifierTypeTokens
				.Select(mod => this.basicInfo.module.ResolveType(mod))
				.ToArray()
				;
		}
		public override Type[] GetOptionalCustomModifiers()
		{
			return this.LoadOptionalModifiers();
			//return this._optionalModifiers.Value;
		}

		//private Lazy<Type[]> _requiredModifiers;
		private Type[] LoadRequiredModifiers()
		{
			if (this.signature.customModifiers == null)
				return Type.EmptyTypes;

			return this.signature.customModifiers.RequiredModifierTypeTokens
				.Select(mod => this.basicInfo.module.ResolveType(mod))
				.ToArray()
				;
		}
		public override Type[] GetRequiredCustomModifiers()
		{
			return this.LoadRequiredModifiers();
			//return this._requiredModifiers.Value;
		}
		public override string Name
		{
			get { return this._name; }
		}
	}
}
